package com.xci.core.helper;

import cn.hutool.core.lang.Assert;
import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
import java.util.Map;

/**
 * JwtToken操作类
 * @author 吕艳阳
 */
public class JwtHelper {
    /**
     * 生成jwt令牌
     * @param data 写入的数据
     * @param secretKey 加密密钥
     * @param expireDate 过期时间
     */
    public static String create(Map<String, Object> data, String secretKey, Date expireDate) {
        Assert.notEmpty(data);
        // 签名算法
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 生成签发时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        // 通过秘钥签名JWT
        byte[] apiKeySecretBytes = Base64.decodeBase64(secretKey);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        // iss: jwt签发者
        // sub: jwt所面向的用户
        // aud: 接收jwt的一方
        // exp: jwt的过期时间，这个过期时间必须要大于签发时间
        // nbf: 定义在什么时间之前，该jwt都是不可用的
        // iat: jwt的签发时间
        // jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击
        JwtBuilder builder = Jwts.builder().setClaims(data).setIssuedAt(now).signWith(signatureAlgorithm, signingKey);

        if(expireDate != null) {
            builder.setExpiration(expireDate).setNotBefore(now);
        }
        return builder.compact();
    }

    /**
     * 解析jwt
     * @param token 令牌字符串
     * @param secretKey 加密密钥
     */
    public static Map<String, Object> parse(String token, String secretKey) {
        try {
            return Jwts.parser().setSigningKey(Base64.decodeBase64(secretKey)).parseClaimsJws(token).getBody();
        }catch(SignatureException e) {
            throw new JwtException("认证签名错误", e);
        }catch(ExpiredJwtException e) {
            throw new JwtException("认证签名过期", e);
        }catch(MalformedJwtException e) {
            throw new JwtException("认证签名格式错误", e);
        }catch(IllegalArgumentException e) {
            throw new JwtException("认证签名参数错误", e);
        } catch(Exception e) {
            throw new JwtException("无效的认证签名", e);
        }
    }
}